package com.paradogs.framework.gate;

import com.paradogs.framework.core.events.PlayerClientActiveEvent;
import com.paradogs.framework.core.events.PlayerClientInactiveEvent;
import com.paradogs.framework.core.msg.ByteData;
import com.paradogs.framework.core.msg.PRMsgContextHolder;
import com.paradogs.framework.core.netty.PRConnHolder;
import com.paradogs.framework.core.netty.server.PRAbServerMsgHandler;
import com.paradogs.framework.core.netty.server.PRConnection;
import com.paradogs.framework.core.netty.server.ServerProperties;
import com.paradogs.framework.core.utils.EventUtils;
import com.paradogs.framework.core.utils.IPUtils;
import com.paradogs.framework.core.utils.MsgUtils;
import com.paradogs.framework.core.utils.StringUtils;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.CompletableFuture;

/**
 * @author: yumi
 * @date: 2023/8/8  8:56
 * @Description: TODO
 */
@Slf4j
@Component
@ChannelHandler.Sharable
public class GateServerMsgHandler extends PRAbServerMsgHandler<ByteData> {

    @Autowired
    private ServerProperties serverProperties;

    @Override
    protected void setProps(ChannelHandlerContext ctx, ByteData msg) {
        super.setProps(ctx, msg);
        GateChannelHolder.Session session = GateChannelHolder.getSession(ctx.channel());
        if (session != null) {
            msg.getMsgHeader().setPId(session.getPlayerId());
        }
        if (StringUtils.isBlank(msg.getMsgHeader().getSendServer())) {
            msg.getMsgHeader().setSendServer("player");
        }
    }

    /**
     * 转发玩家消息
     * @param msg
     * @throws Exception
     */
    @Override
    protected void processMsg(ByteData msg) throws Exception {
        if (msg.getMsgHeader().getServer().equals(serverProperties.getType())) {
            MsgUtils.adapterHandle(msg);
            return;
        }
        // 收到回复消息后返回给玩家
        // 待优化：如果 logic 方法没有返回值，这里会无限等待，内存溢出
        CompletableFuture<byte[]> promise = new CompletableFuture<>();
        promise.thenAccept(data -> {
            // 回复客户端
            MsgUtils.send("player", data, PRMsgContextHolder.getChannel());
        });
        // 转发到对应服务器
        MsgUtils.gateRequest(msg.getMsgHeader(), msg.getDataBytes(), byte[].class, promise);
    }

    /**
     * 连接建立事件
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        GateChannelHolder.init(ctx.channel());
        EventUtils.publishEvent(new PlayerClientActiveEvent(ctx));
        log.info("PlayerClient connect: {}", IPUtils.getAddr(ctx.channel()));
    }

    /**
     * 连接断开事件
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        GateChannelHolder.remove(ctx.channel());
        EventUtils.publishEvent(new PlayerClientInactiveEvent(ctx));
        log.info("PlayerClient disconnect: {}", IPUtils.getAddr(ctx.channel()));
    }

}
